﻿/*************************************************************************
 * Created by OhZee Creative, LLC
 * 2013
 * This code is licensed under Microsoft Public License (Ms-PL)
 * http://opensource.org/licenses/ms-pl
 * http://ozframework.codeplex.com/
 *************************************************************************/

// TODO:
// App.ViewModel.IdleDetectionManager.Push();
// App.ViewModel.IdleDetectionManager.Pop();

namespace OhZeeCreative.Sound.Windows8
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    using OhZeeCreative.Sound.Core;

    public class SoundManager : ISoundManager
    {
        private SoundChannelCollection channels;
        private SoundRequestCollection requests;

        public SoundManager(int polyPhony)
        { 
            this.channels = new SoundChannelCollection(polyPhony);
            this.requests = new SoundRequestCollection();

            foreach (SoundChannel item in this.channels.Items)
            {
                item.MediaElement.MediaEnded += me_MediaEnded;
                item.MediaElement.MediaFailed += MediaElement_MediaFailed;
            }
        }

		public void SetParent(Panel panel)
		{
			this.channels.SetParent(panel);
		}

        void MediaElement_MediaFailed(object sender, ExceptionRoutedEventArgs e)
        {
            Debug.WriteLine(e.ErrorMessage);
        }

        private void me_MediaEnded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            this.PlayNext();            
        }

        private void PlayNext()
        {
            // Don't use Play() because it will cause the sound to go back to the queue
            SoundChannel channel = this.channels.GetFreeChannel();
            if (channel != null)
            {
                SoundRequest request = this.requests.Fetch();
                if (request != null)
                {
                    channel.Play(request);
                }
            }
        }

        public int Play(SoundItem item, bool ensureImmediatePlay = true)
        {
            int id = -1;

            if (item != null)
            {
                SoundChannel channel = this.channels.GetFreeChannel();
                if (channel == null)
                {
                    if (ensureImmediatePlay)
                    {
                        channel = this.channels.MakeFreeChannel();

                        if (channel == null)
                        {
                            Debug.Assert(false, "Could not ensure immediate play");
                            return -1;
                        }
                        else
                        {
                            id = this.requests.Add(item);
                            return id;
                        }
                    }
                }

                Debug.Assert(channel != null);
                
                id = this.requests.Bypass();
                channel.Play(new SoundRequest(item, id));
            }
            return id;
        }

        public bool Stop(int id)
        {
            foreach (SoundChannel channel in this.channels.Items)
            {
                if (channel.SoundRequest.Id == id)
                {
                    channel.Stop();
                    return true;
                }
            }

            return false;
        }

        public int GetPlayingCount(SoundItem item)
        {
            return this.channels.Items.Count((channel) => channel.IsBusy);
        }

        public void StopAll()
        {
            foreach (SoundChannel channel in this.channels.Items)
            {
                channel.Stop();
            }
        }

		public bool Play(ISoundItem sound)
		{
			return this.Play((SoundItem) sound, ensureImmediatePlay: true) >= 0;
		}

		public bool Stop(ISoundItem sound)
		{
			throw new NotImplementedException();
		}

		public int GetPlayingCount(ISoundItem item)
		{
			throw new NotImplementedException();
		}
	}
}
